home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / MailManager / MailManager.m < prev    next >
Encoding:
Text File  |  1993-03-28  |  32.4 KB  |  1,369 lines

  1. /*
  2.  * Program:    Distributed Electronic Mail Manager (MailManager object)
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    17 February 1989
  13.  * Last Edited:    28 March 1993
  14.  *
  15.  * Copyright 1993 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.  
  37. #import "MailManager.h"
  38. #import "XTextPkg.h"    // mdd
  39.  
  40. @implementation MailManager
  41.  
  42. // Minimum sane check interval
  43. #define sane 30
  44.  
  45. // mdd begin
  46.  
  47. id xtext_action = nil;
  48. id read_action;
  49.  
  50. // mdd end
  51.  
  52. // Initialization.  We can't use the "initialize" factory method because we
  53. // want to get at appName, which is set up by Application's "new" factory
  54. // method.
  55.  
  56. // Helper macro for defaults that are string "YES" or "NO"
  57.  
  58. #define YESNO(Q) !strcmp (ucase (strcpy (s,NXGetDefaultValue (n,Q))),"YES")
  59.  
  60. + new
  61. {
  62.   struct hostent *host_name;
  63.   char s[TMPLEN],h[TMPLEN],u[TMPLEN];
  64.   char *t;
  65.   const char *n;
  66.   NXDefaultsVector defaults = {
  67.     {"AutomaticExpunge","NO"},
  68.     {"AutomaticLogin","NO"},
  69.     {"AutomaticOpen","NO"},
  70.     {"AutomaticRead","NO"},
  71.     {"AutomaticZoom","NO"},
  72.     {"CheckInterval","300"},
  73.     {"CloseFinalKill","NO"},
  74.     {"DebugProtocol","NO"},
  75.     {"DefaultBccList",""},
  76.     {"DefaultCcList",""},
  77.     {"DomainName",h},
  78.     {"NXFixedPitchFont","Ohlfs"},
  79.     {"NXFixedPitchFontSize","10.0"},
  80.     {"LiteralDisplay","NO"},
  81.     {"MailboxFormat","mbox"},
  82.     {"MTPServer","localhost"},
  83.     {"NoLineBreaking","NO"},
  84.     {"NoPersonalNames","NO"},
  85.     {"OutBox",""},
  86.     {"PersonalName",s},
  87.     {"Repository",""},
  88.     {"UserName",u},
  89.     {"KeyBindings",""},        // mdd
  90.     {"KeyBase",""},            // mdd
  91.     {"ReadBBoards","YES"},        // mdd
  92.     {NIL}
  93.   };
  94.   self = [super new];
  95.   n = [self appName];
  96.   mail_link (&imapdriver);    // get IMAP driver
  97.   mail_link (&tenexdriver);    // get Tenex mail driver
  98.   mail_link (&mhdriver);    // get mh mail driver
  99.   mail_link (&mboxdriver);    // get mbox mail driver
  100.   mail_link (&bezerkdriver);    // get Berkeley mail driver
  101.   mail_link (&newsdriver);    // get news driver
  102.   mail_link (&nntpdriver);    // get NNTP driver
  103.   mail_link (&dummydriver);    // get dummy mail driver
  104.   gethostname (s,TMPLEN-1);    // get local host name
  105.                 // get it in full form
  106.   strcpy (h,localhost =
  107.       cpystr ((host_name = gethostbyname (s)) ? host_name->h_name : s));
  108.                 // get login user name
  109.   strcpy (u,(localuser = cpystr ((char *) NXUserName ())));
  110.                 // get personal name poop
  111.   strcpy (s,(getpwnam (localuser))->pw_gecos);
  112.                 // dyke out the office and phone poop
  113.   if (t = (char *) strchr (s,',')) t[0] = '\0';
  114.   localpersonal = cpystr (s);    // now copy personal name
  115.  
  116.                 // register defaults
  117.   NXRegisterDefaults (n,defaults);
  118.                 // get all defaults
  119.   defaultfont = [Font newFont:NXGetDefaultValue (n,"NXFixedPitchFont")
  120.          size:atof (NXGetDefaultValue (n,"NXFixedPitchFontSize"))];
  121.   domainname = NXGetDefaultValue (n,"DomainName");
  122.   mtpserver = NXGetDefaultValue (n,"MTPServer");
  123.   personalname = NXGetDefaultValue (n,"PersonalName");
  124.   repository = NXGetDefaultValue (n,"Repository");
  125.   username = NXGetDefaultValue (n,"UserName");
  126.   defaultbcc = NXGetDefaultValue (n,"DefaultBccList");
  127.   defaultcc = NXGetDefaultValue (n,"DefaultCcList");
  128.   outbox = NXGetDefaultValue (n,"OutBox");
  129.   autoexpunge = YESNO ("AutomaticExpunge");
  130.   autologin = YESNO ("AutomaticLogin");
  131.   autoopen = YESNO ("AutomaticOpen");
  132.   autoread = YESNO ("AutomaticRead");
  133.   autozoom = YESNO ("AutomaticZoom");
  134.   closefinalkill = YESNO ("CloseFinalKill");
  135. // mdd begin
  136.   xtext_action = [[XTDispatchAction allocFromZone:[self zone]]
  137.                       initBase:NXGetDefaultValue(n,"KeyBase")
  138.                     estream:nil];
  139.   [xtext_action addBindings:NXGetDefaultValue(n,"KeyBindings")
  140.                   estream:nil];
  141.   read_action = [[xtext_action copy]
  142.                     addBindings:"'n=nextMsg:0;'p=prevMsg;"
  143.                         "'d=deleteMsg:2;'k={deleteMsg:1;nextMsg:1}"
  144.                     estream:nil];
  145.   readbboards = YESNO ("ReadBBoards");
  146. // mdd end
  147.   debug = YESNO ("DebugProtocol");
  148.   if (format = strcmp ("mbox",lcase
  149.                (strcpy (s,NXGetDefaultValue (n,"MailboxFormat")))))
  150.     if (!(format = !strcmp ("mtxt",s)))
  151.       mm_log ("Unknown mailbox format in defaults, using mbox",ERROR);
  152.   literaldisplay = YESNO ("LiteralDisplay");
  153.   nolinebreaking = YESNO ("NoLineBreaking");
  154.   nopersonal = YESNO ("NoPersonalNames");
  155.   interval = atof (NXGetDefaultValue (n,"CheckInterval"));
  156.                 // sanity check on the interval
  157.   interval = interval > 0 ? (interval < sane ? sane : interval) : 0;
  158.   return self;            // return ourselves
  159. }
  160.  
  161. // Initiate our event loop
  162. //
  163. // Application instance variables get set here
  164.  
  165. - run
  166. {
  167.   pasteboard = [Pasteboard new];// note our pasteboard
  168.                 // none of these panels loaded yet
  169.   filePanel = infoPanel = preferencesPanel = book = helpPanel =
  170.     addressHelpPanel = mboxHelpPanel = selectHelpPanel = readHelpPanel =
  171.       sendHelpPanel = NIL;
  172.   if (autoopen) {        // want automatic open?
  173.     MAILSTREAM *stream;
  174.     char tmp[TMPLEN];
  175.     const char *repository = NXGetDefaultValue ([NXApp appName],"Repository");
  176.     [self activateSelf:T];    // make us the active application
  177.     if (*repository)        // yes, build default mailbox
  178.       sprintf (tmp,"{%s}INBOX",repository);
  179.     else strcpy (tmp,"INBOX");
  180.                 // try to open it
  181.     if (stream = mail_open (NIL,tmp,debug ? OP_DEBUG : NIL))
  182.       opener = [[MBoxWindow new] setStream:stream];
  183.   }
  184.   [super run];            // now initiate our event loop
  185.   return self;
  186. }
  187.  
  188. // mdd begin
  189. /*
  190.  * Application object delegate methods.
  191.  * Since we don't have an application delegate, messages that would
  192.  * normally be sent there are sent to the Application object itself instead.
  193.  */
  194.  
  195. - appDidInit:sender
  196. {
  197.     [telemetryMenuItem setUpdateAction:@selector(updateTelemetryMenu:)
  198.                      forMenu:[windowMenu target]];
  199.     [[windowMenu target] setAutoupdate:YES];
  200.     [[telemetryView window] setExcludedFromWindowsMenu:YES];
  201.     return self;
  202. }
  203.  
  204. // mdd end
  205.  
  206. // Main Menu commands
  207.  
  208.  
  209. // Compose a message
  210.  
  211. - compose:sender
  212. {
  213.                 // spawn a SendWindow
  214.   return [SendWindow new];
  215. }
  216.  
  217.  
  218. // Open a mailbox
  219.  
  220. - open:sender
  221. {
  222.                 // do new mailbox command if locked
  223.   if (lockedopen && opener) [opener newMailbox:self];
  224.                 // want another mailbox window
  225.   else [self reOpen:NIL window:NIL];
  226.   return self;
  227. }
  228.  
  229.  
  230. // Close a mailbox
  231.  
  232. - close
  233. {
  234.   opener = NIL;            // this mailbox is history
  235.   return self;
  236. }
  237.  
  238. // Open a new window on the same stream, possibly different mailbox
  239.  
  240. - reOpen:(MAILSTREAM *) stream window:old
  241. {
  242.   const char *host;
  243.   char tmp[TMPLEN];
  244.   NXCoord x = 0;
  245.   NXCoord y = 0;
  246.   if (old) {            // window position is on top of old one
  247.     NXRect frame;
  248.                 // get old frame
  249.     [[old window] getFrame:&frame];
  250.     x = NX_X (&frame); y = NX_Y (&frame);
  251.   }
  252.   if (stream) {            // have an old stream?
  253.                 // yes, network connection?
  254.     if (mail_valid_net (stream->mailbox,stream->dtb,tmp,NIL))
  255.       [mailboxHost setStringValue:tmp];
  256.     else [mailboxHost setStringValue:""];
  257.   }
  258.                 // default host is repository if no stream
  259.   else [mailboxHost setStringValue:repository];
  260.                 // default mailbox is always INBOX
  261.   [mailboxMailbox setStringValue:"INBOX"];
  262.                 // put the user into the responder
  263.   [mailboxSelection makeFirstResponder:mailboxResponder];
  264.                 // select the mailbox field of it
  265.   [mailboxResponder selectCellAt:1 :0];
  266.                 // do the mailbox selection
  267.   [NXApp runModalFor:mailboxSelection];
  268.  
  269.   if (OK) {            // got a mailbox?
  270.                 // yes, have host name?
  271.     if (*(host = [mailboxHost stringValue]))
  272.       sprintf (tmp,"{%s}%s",host,[mailboxMailbox stringValue]);
  273.                 // else do it the simple way
  274.     else strcpy (tmp,[mailboxMailbox stringValue]);
  275.     opener = NIL;        // zap the old opener
  276.     if (old) [old close];    // nuke the old window
  277.                 // drop any old streamprop now
  278.     if (stream) putstreamprop (stream,NIL);
  279.                 // got a connection?
  280.     if (stream = mail_open (stream,(char *) tmp,debug ? OP_DEBUG : NIL)) {
  281.                 // create window at proper position
  282.       [[(opener = [MBoxWindow new]) window] moveTo:x :y];
  283.       [opener setStream:stream];// give it our stream
  284.                 // add mailbox to browser unless local INBOX
  285.       if (strcmp (ucase (tmp),"INBOX"))
  286.     [self addMailboxToBrowser:stream->mailbox];
  287.     }
  288.   }
  289.   return self;
  290. }
  291.  
  292. // Add new mailbox to browser
  293.  
  294. - addMailboxToBrowser:(char *) name
  295. {
  296.   int i;
  297.   int rows,cols;
  298.   char mbx[TMPLEN],title[TMPLEN];
  299.                 // only if really opened a mailbox!
  300.   if (name && !strstr (name,"<no mailbox>")) {
  301.                 // get the number of rows and columns
  302.     [browser getNumRows:&rows numCols:&cols];
  303.     strcpy (mbx,name);        // copy mailbox name
  304.     ucase (mbx);        // make an all-uppercase copy
  305.     for (i = 0; i < rows; ++i) {// look through existing mailboxes
  306.                 // get its title
  307.       strcpy (title,[[browser cellAt:i :0] title]);
  308.                 // if matches then don't add it
  309.       if (!(strcmp (mbx,ucase (title)))) return NIL;
  310.     }
  311.     [browser addRow];        // add it to mailbox list
  312.     [browser setTitle:name at:rows :--cols];
  313.                 // resize the browser to hold it
  314.     [[browser sizeToCells] display];
  315.   }
  316.   return self;
  317. }
  318.  
  319.  
  320. // Called at initialization to note the mailbox selection panel
  321.  
  322. - setMailboxSelection:anObject
  323. {
  324.   mailboxSelection = anObject;    // note the mailbox selection panel
  325.   return self;            // standard return
  326. }
  327.  
  328. // Called at initialization to note the mailboxes browser
  329.  
  330. - setMailboxes:anObject
  331. {
  332.   const char *repository = NXGetDefaultValue ([NXApp appName],"Repository");
  333.   char tmp[TMPLEN];
  334.   NXRect frame;
  335.   NXSize size;
  336.   id cell;
  337.   [anObject getFrame:&frame];    // get frame of our message items view
  338.                 // create a scroll view of it
  339.   [mailboxes = [ScrollView newFrame:&frame] setBorderType:NX_BEZEL];
  340.                 // only vertical scrolling is required
  341.   [mailboxes setVertScrollerRequired:T];
  342.                 // allow its size to change
  343.   [mailboxes setAutosizing:NX_HEIGHTSIZABLE|NX_WIDTHSIZABLE];
  344.                 // make it the view
  345.   [[anObject superview] replaceSubview:anObject with:mailboxes];
  346.                 // get the size minus the scroll bars
  347.   [mailboxes getContentSize:&size];
  348.                 // set it as such in the mailbox browser frame
  349.   NX_WIDTH (&frame) = size.width; NX_HEIGHT (&frame) = size.height;
  350.   if (*repository) sprintf (tmp,"{%s}INBOX",repository);
  351.   else strcpy (tmp,"INBOX");    // make the initial default mailbox
  352.   cell = [[ButtonCell newTextCell:tmp] setAlignment:NX_LEFTALIGNED];
  353.                 // create the browser
  354.   browser = [Matrix newFrame:&frame mode:NX_RADIOMODE prototype:cell
  355.          numRows:1 numCols:1];
  356.                 // allow empty selection
  357.   [browser setEmptySelectionEnabled:T];
  358.   [cell calcCellSize:&size];    // get the minimum cell size
  359.   size.width = 2000;        // make cells superwide
  360.   [browser setCellSize:&size];    // set the cell size
  361.                 // no intercell spacing
  362.   size.width = 0; size.height = 0;
  363.   [browser setIntercell:&size];
  364.   [browser sizeToCells];    // resize the browser
  365.   [browser setAutosizing:NX_WIDTHSIZABLE];
  366.   [browser setAutosizeCells:T];    // autosize
  367.   [browser setAutoscroll:T];    // make it autoscrolling
  368.   [browser validateSize:T];
  369.                 // done once a mailbox is moused
  370.   [browser setAction:@selector(selectLoad:)];
  371.   [[browser setDoubleAction:@selector(mailboxOK:)] setTarget:self];
  372.   mail_find (NIL,"*");        // find local mailboxes
  373.   if (readbboards)        // find local bboards
  374.     mail_find_bboards (NIL,"*");
  375.                 // put up the display
  376.   [[mailboxes setDocView:browser] display];
  377.   return self;            // standard return
  378. }
  379.  
  380. // Called at initialization to note the mailbox responder
  381.  
  382. - setMailboxResponder:anObject
  383. {
  384.   mailboxResponder = anObject;    // note the mailbox query responder
  385.   return self;
  386. }
  387.  
  388.  
  389. // Called at initialization to note the mailbox host
  390.  
  391. - setMailboxHost:anObject
  392. {
  393.   mailboxHost = anObject;    // note the mailbox host
  394.   return self;
  395. }
  396.  
  397.  
  398. // Called at initialization to note the mailbox mailbox
  399.  
  400. - setMailboxMailbox:anObject
  401. {
  402.   mailboxMailbox = anObject;    // note the mailbox mailbox
  403.   return self;
  404. }
  405.  
  406. // Load name from existing mailbox
  407.  
  408. - selectLoad:sender
  409. {
  410.   int i = 0;
  411.   char host[MAILTMPLEN];
  412.   const char *box;
  413.   const char *mailbox = [[sender selectedCell] title];
  414.   if (mailbox) {        // make sure we got something!
  415.                 // network mailbox?
  416.     if (*mailbox == '{' && (box = 1+strchr (mailbox,'}')) &&
  417.     (i = box-mailbox-2)) strncpy (host,mailbox+1,i);
  418.     else box = mailbox;        // local mailbox
  419.       host[i] = '\0';        // tie off host string
  420.                 // set the values
  421.     [mailboxHost setStringValue:(const char *) host];
  422.     [mailboxMailbox setStringValue:box];
  423.                 // put the user into the responder
  424.     [mailboxSelection makeFirstResponder:mailboxResponder];
  425.                 // select the mailbox field of it
  426.     [mailboxResponder selectCellAt:1 :0];
  427.   }
  428.   return self;
  429. }
  430.  
  431.  
  432. // User wants to cancel mailbox
  433.  
  434. - mailboxCancel:sender;
  435. {
  436.   [NXApp stopModal];        // end the modality
  437.   [mailboxSelection close];    // close the select panel
  438.   OK = NIL;            // warui keredo KYANSERU!
  439.   return self;
  440. }
  441.  
  442.  
  443. // User confirms new mailbox
  444.  
  445. - mailboxOK:sender
  446. {
  447.   [NXApp stopModal];        // end the modality
  448.   [mailboxSelection close];    // close the select panel
  449.   OK = T;            // daijoubu dayo
  450.   return self;
  451. }
  452.  
  453. // Login management
  454.  
  455.  
  456. // Called at initialization to note the login panel
  457.  
  458. - setLogin:anObject
  459. {
  460.   login = anObject;        // note the login panel
  461.   return self;
  462. }
  463.  
  464.  
  465. // Called at initialization to note the login box
  466.  
  467. - setLoginBox:anObject
  468. {
  469.   loginBox = anObject;        // note the login query box
  470.   return self;
  471. }
  472.  
  473.  
  474. // Called at initialization to note the login responder
  475.  
  476. - setLoginResponder:anObject
  477. {
  478.   loginResponder = anObject;    // note the login query responder
  479.   return self;
  480. }
  481.  
  482.  
  483. // Called at initialization to note the user name field
  484.  
  485. - setUserName:anObject
  486. {
  487.   userName = anObject;        // note the user name field
  488.   return self;
  489. }
  490.  
  491.  
  492. // Called at initialization to note the password field
  493.  
  494. - setPassword:anObject
  495. {
  496.   password = anObject;        // note the password field
  497.   [password setTextGray:1.0];    // passwords should not be visible
  498.   return self;
  499. }
  500.  
  501. // Put up a login panel
  502.  
  503. - login:(char *) host user:(char *) user password:(char *) pwd force:(BOOL) f
  504. {
  505.   char c = *username;
  506.                 // clear last login username
  507.   if (lastlogin) fs_give ((void **) &lastlogin);
  508.   lastlogin = NIL;
  509.                 // user name defaults from preferences
  510.   [userName setStringValue:username];
  511.                 // skip panel if not forced and can autologin
  512.   if (f || !(autologin && c && *[password stringValue])) {
  513.     [loginBox setTitle:host];    // set up new title for box
  514.     [loginBox display];
  515.                 // put the user into the responder
  516.     [login makeFirstResponder:loginResponder];
  517.                 // if no user name zap any previous password
  518.     if (!c) [password setStringValue:""];
  519.                 // select appropriate field
  520.     [loginResponder selectCellAt:(c ? 1 : 0) :0];
  521.     [NXApp runModalFor:login];    // modally invoke the login panel
  522.   }
  523.                 // return what the user wants
  524.   strcpy (user,[userName stringValue]);
  525.   strcpy (pwd,[password stringValue]);
  526.   lastlogin = cpystr (user);    // remember last login user name
  527.   return self;
  528. }
  529.  
  530.  
  531. // Login is ready
  532.  
  533. - loginOK:sender
  534. {
  535.   char c;
  536.                 // login completed?
  537.   if ((c = *[userName stringValue]) && *[password stringValue]) {
  538.     [NXApp stopModal];        // yes, end the modality
  539.     [login close];        // close the login panel
  540.   }
  541.                 // otherwise put cursor at missing field
  542.   else [loginResponder selectCellAt:(c ? 1 : 0) :0];
  543.   return self;
  544. }
  545.  
  546. // Telemetry management
  547.  
  548.  
  549. // Called at initialization to note the telemetry view
  550.  
  551. - setTelemetryView:anObject
  552. {
  553.   NXRect frame;
  554.   //  Make the scroller be window's content view, so resizing the window
  555.   // will resize the scroller
  556.   [[anObject window] setContentView:anObject];
  557.                 // note telemetry view and get its frame
  558.   [(telemetryView = [anObject docView]) getFrame:&frame];
  559.                 // reset its font
  560.   [telemetryView renewFont:defaultfont text:"" frame:&frame tag:0];
  561.                 // don't display until ready
  562.   [telemetryView setAutodisplay:NIL];
  563.                 // telemetry is read-only
  564.   [telemetryView setEditable:NIL];
  565.   [telemetryView setNoWrap];    // set up wrapping by characters
  566.   [telemetryView setCharWrap:T];
  567.   return self;            // standard return
  568. }
  569.  
  570.  
  571. // Send a string to the telemetry window
  572.  
  573. - telemetry:(char *)string
  574. {
  575.   int i = [telemetryView textLength];
  576.   [telemetryView setSel:i :i];    // select end of text
  577.                 // prepend with newline if not first time
  578.   if (i) [telemetryView replaceSel:"\n"];
  579.                 // output the string
  580.   [telemetryView replaceSel:string];
  581.                 // make sure the string can be seen
  582.   [telemetryView scrollSelToVisible];
  583.   [telemetryView display];    // now display the telemetry
  584.   return self;
  585. }
  586.  
  587. // Printing
  588.  
  589.  
  590. // Note the printer
  591.  
  592. - setPrinter:anObject
  593. {
  594.   printer = [anObject docView];    // note our printer
  595.   return self;
  596. }
  597.  
  598.  
  599. // Initialize the printer
  600.  
  601. - startPrint
  602. {
  603.   NXRect frame;
  604.   [printer getFrame:&frame];    // get printer's frame
  605.                 // reset its font
  606.   [printer renewFont:defaultfont text:"" frame:&frame tag:0];
  607.   [printer setSel:0 :0];    // initialize selection
  608.   return self;
  609. }
  610.  
  611.  
  612. // Add text to the printer
  613.  
  614. - printText:(char *) text
  615. {
  616.   [printer replaceSel:text];    // add text to the printer
  617.   return self;
  618. }
  619.  
  620.  
  621. // Print the stuff in the printer
  622.  
  623. - print
  624. {
  625.   [printer printPSCode:self];    // print the works
  626.   return self;
  627. }
  628.  
  629. // File management
  630.  
  631.  
  632. // Note our file panel
  633.  
  634. - setFilePanel:anObject
  635. {
  636.   filePanel = anObject;        // note our file panel
  637.   return self;
  638. }
  639.  
  640.  
  641. // Note our file destination
  642.  
  643. - setFileDestination:anObject
  644. {
  645.   fileDestination = anObject;    // note our file destination
  646.   return self;
  647. }
  648.  
  649.  
  650. // Note our local file button
  651.  
  652. - setFileLocal:anObject
  653. {
  654.   fileLocal = anObject;        // note our local file button
  655.   return self;
  656. }
  657.  
  658. // Get file name
  659.  
  660. - (char *) getFile
  661. {
  662.   char tmp[TMPLEN];
  663.   const char *s;
  664.                 // create file panel if don't have one
  665.   if (!filePanel) [NXApp loadNibSection:"FilePanel.nib"
  666.                owner:self withNames:NIL];
  667.   sprintf (tmp,"%s Format Mailbox on this NeXT",format ? "Tenex" : "Berkeley");
  668.   [fileLocal setTitle:tmp];    // update title as appropriate
  669.   [fileDestination selectText:self];
  670.   [NXApp runModalFor:filePanel];// put up the file panel
  671.                 // quit if not OK or no file
  672.   if (!(OK && *(s = [fileDestination stringValue]))) return NIL;
  673.   if ([fileLocal state]) sprintf (tmp,"*%s",s);
  674.   else sprintf (tmp," %s",s);
  675.   return (cpystr (tmp));    // return the file
  676. }
  677.  
  678.  
  679. // User wants to cancel file operation
  680.  
  681. - fileCancel:sender
  682. {
  683.   [NXApp stopModal];        // end the modality
  684.   [filePanel close];        // close the file panel
  685.   OK = NIL;            // not OK
  686.   return self;
  687. }
  688.  
  689.  
  690. // User wants to go ahead with file operation
  691.  
  692. - fileOK:sender
  693. {
  694.   [NXApp stopModal];        // end the modality
  695.   [filePanel close];        // close the file panel
  696.   OK = T;            // OK to do whatever
  697.   return self;
  698. }
  699.  
  700. // Called at initialization to note the help panel
  701.  
  702. - setHelpPanel:anObject;
  703. {
  704.   helpPanel = anObject;
  705.   return self;
  706. }
  707.  
  708.  
  709. // Open the help panel
  710.  
  711. - help:sender
  712. {
  713.                 // create help panel if don't have one
  714.   if (!helpPanel) [NXApp loadNibSection:"HelpPanel.nib"
  715.            owner:self withNames:NIL];
  716.   [helpPanel orderFront:self];    // open it
  717.   return self;
  718. }
  719.  
  720.  
  721. // Called at initialization to set the address help panel
  722.  
  723. - setAddressHelpPanel:anObject
  724. {
  725.   addressHelpPanel = anObject;    // set the address help panel
  726.   return self;
  727. }
  728.  
  729.  
  730. // Open the address help panel
  731.  
  732. - addressHelp:sender
  733. {
  734.   if (!addressHelpPanel)    // create new help panel if none yet
  735.     [NXApp loadNibSection:"AddressHelpPanel.nib" owner:self withNames:NIL];
  736.   [addressHelpPanel orderFront:self];
  737.   return self;
  738. }
  739.  
  740. // Called at initialization to set the mbox help panel
  741.  
  742. - setMboxHelpPanel:anObject
  743. {
  744.   mboxHelpPanel = anObject;    // set the mbox help panel
  745.   return self;
  746. }
  747.  
  748.  
  749. // Open the mbox help panel
  750.  
  751. - mboxHelp:sender
  752. {
  753.   if (!mboxHelpPanel)        // create new help panel if none yet
  754.     [NXApp loadNibSection:"MBoxHelpPanel.nib" owner:self withNames:NIL];
  755.   [mboxHelpPanel orderFront:self];
  756.   return self;
  757. }
  758.  
  759.  
  760. // Called at initialization to set the select help panel
  761.  
  762. - setSelectHelpPanel:anObject
  763. {
  764.   selectHelpPanel = anObject;    // set the select help panel
  765.   return self;
  766. }
  767.  
  768.  
  769. // Open the select help panel
  770.  
  771. - selectHelp:sender
  772. {
  773.   if (!selectHelpPanel)        // create new help panel if none yet
  774.     [NXApp loadNibSection:"SelectHelpPanel.nib" owner:self withNames:NIL];
  775.   [selectHelpPanel orderFront:self];
  776.   return self;
  777. }
  778.  
  779. // Called at initialization to set the read help panel
  780.  
  781. - setReadHelpPanel:anObject
  782. {
  783.   readHelpPanel = anObject;    // set the read help panel
  784.   return self;
  785. }
  786.  
  787.  
  788. // Open the read help panel
  789.  
  790. - readHelp:sender
  791. {
  792.   if (!readHelpPanel)        // create new help panel if none yet
  793.     [NXApp loadNibSection:"ReadHelpPanel.nib" owner:self withNames:NIL];
  794.   [readHelpPanel orderFront:self];
  795.   return self;
  796. }
  797.  
  798.  
  799. // Called at initialization to set the send help panel
  800.  
  801. - setSendHelpPanel:anObject
  802. {
  803.   sendHelpPanel = anObject;    // set the send help panel
  804.   return self;
  805. }
  806.  
  807.  
  808. // Open the send help panel
  809.  
  810. - sendHelp:sender
  811. {
  812.   if (!sendHelpPanel)    // create new help panel if none yet
  813.     [NXApp loadNibSection:"SendHelpPanel.nib" owner:self withNames:NIL];
  814.   [sendHelpPanel orderFront:self];
  815.   return self;
  816. }
  817.  
  818.  
  819.  
  820. // Called at initialization to note the info panel
  821.  
  822. - setInfoPanel:anObject;
  823. {
  824.   infoPanel = anObject;
  825.   return self;
  826. }
  827.  
  828.  
  829. // Open the info panel
  830.  
  831. - info:sender
  832. {
  833.                 // create info panel if don't have one
  834.   if (!infoPanel) [NXApp loadNibSection:"InfoPanel.nib"
  835.            owner:self withNames:NIL];
  836.   [infoPanel orderFront:self];    // open it
  837.   return self;
  838. }
  839.  
  840. // Preferences management
  841.  
  842.  
  843. // Called at initialization to note the preferences panel
  844.  
  845. - setPreferencesPanel:anObject
  846. {
  847.   preferencesPanel = anObject;
  848.   return self;
  849. }
  850.  
  851.  
  852. // Called at initialization to note the preferences panel help
  853.  
  854. - setPreferencesHelp:anObject;
  855. {
  856.   preferencesHelp = anObject;
  857.   return self;
  858. }
  859.  
  860.  
  861. // Called at initialization to note the preferences panel domain name
  862.  
  863. - setPrefDomainName:anObject
  864. {
  865.   [(prefDomainName = anObject) setStringValue:domainname];
  866.   return self;
  867. }
  868.  
  869.  
  870. // Called at initialization to note the preferences panel MTP server
  871.  
  872. - setPrefMTPServer:anObject
  873. {
  874.   [(prefMTPServer = anObject) setStringValue:mtpserver];
  875.   return self;
  876. }
  877.  
  878.  
  879. // Called at initialization to note the preferences panel personal name
  880.  
  881. - setPrefPersonalName:anObject
  882. {
  883.   [(prefPersonalName = anObject) setStringValue:personalname];
  884.   return self;
  885. }
  886.  
  887. // Called at initialization to note the preferences panel repository
  888.  
  889. - setPrefRepository:anObject
  890. {
  891.   [(prefRepository = anObject) setStringValue:repository];
  892.   return self;
  893. }
  894.  
  895.  
  896. // Called at initialization to note the preferences panel user name
  897.  
  898. - setPrefUserName:anObject
  899. {
  900.   [(prefUserName = anObject) setStringValue:username];
  901.   return self;
  902. }
  903.  
  904.  
  905. // Called at initialiation to note the preferences panel default bcc list
  906.  
  907. - setDefaultBccList:anObject
  908. {
  909.   [(defaultBccList = anObject) setStringValue:defaultbcc];
  910.   return self;
  911. }
  912.  
  913.  
  914. // Called at initialiation to note the preferences panel default cc list
  915.  
  916. - setDefaultCcList:anObject
  917. {
  918.   [(defaultCcList = anObject) setStringValue:defaultcc];
  919.   return self;
  920. }
  921.  
  922.  
  923. // Called at initialization to note the preferences panel outbox
  924.  
  925. - setOutBox:anObject
  926. {
  927.   [(outBox = anObject) setStringValue:outbox];
  928.   return self;
  929. }
  930.  
  931.  
  932. // Called at initialization to note the mailbox format
  933.  
  934. - setMailboxFormat:anObject
  935. {
  936.   [(mailboxFormat = anObject) selectCellAt:format :0];
  937.   return self;
  938. }
  939.  
  940. // Called at initialization to note the automatic expunge state
  941.  
  942. - setAutomaticExpunge:anObject
  943. {
  944.   [(automaticExpunge = anObject) setIntValue:autoexpunge];
  945.   return self;
  946. }
  947.  
  948.  
  949. // Called at initialization to note the automatic login state
  950.  
  951. - setAutomaticLogin:anObject
  952. {
  953.   [(automaticLogin = anObject) setIntValue:autologin];
  954.   return self;
  955. }
  956.  
  957.  
  958. // Called at initialization to note the automatic open switch
  959.  
  960. - setAutomaticOpen:anObject
  961. {
  962.   [(automaticOpen = anObject) setIntValue:autoopen];
  963.   return self;
  964. }
  965.  
  966.  
  967. // Called at initialization to note the automatic read switch
  968.  
  969. - setAutomaticRead:anObject
  970. {
  971.   [(automaticRead = anObject) setIntValue:autoread];
  972.   return self;
  973. }
  974.  
  975.  
  976. // Called at initialization to note the automatic zoom switch
  977.  
  978. - setAutomaticZoom:anObject
  979. {
  980.   [(automaticZoom = anObject) setIntValue:autozoom];
  981.   return self;
  982. }
  983.  
  984. // Called at initialization to note the close final kill switch
  985.  
  986. - setCloseFinalKill:anObject
  987. {
  988.   [(closeFinalKill = anObject) setIntValue:closefinalkill];
  989.   return self;
  990. }
  991.  
  992.  
  993. // Called at initialization to note the debugging switch
  994.  
  995. - setDebugging:anObject
  996. {
  997.   [(debugging = anObject) setIntValue:debug];
  998.   return self;
  999. }
  1000.  
  1001.  
  1002. // Called at initialization to note the literal display switch
  1003.  
  1004. - setLiteralDisplay:anObject
  1005. {
  1006.   [(literalDisplay = anObject) setIntValue:literaldisplay];
  1007.   return self;
  1008. }
  1009.  
  1010.  
  1011. // Called at initialization to note the no line breaking switch
  1012.  
  1013. - setNoLineBreaking:anObject
  1014. {
  1015.   [(noLineBreaking = anObject) setIntValue:nolinebreaking];
  1016.   return self;
  1017. }
  1018.  
  1019.  
  1020. // Called at initialization to note the no personal names switch
  1021.  
  1022. - setNoPersonalNames:anObject
  1023. {
  1024.   [(noPersonalNames = anObject) setIntValue:nopersonal];
  1025.   return self;
  1026. }
  1027.  
  1028.  
  1029. // Called at initialization to note the check interval
  1030.  
  1031. - setCheckInterval:anObject
  1032. {
  1033.   [(checkInterval = anObject) setDoubleValue:interval];
  1034.   return self;
  1035. }
  1036.  
  1037. // Change domain name
  1038.  
  1039. - domainName:sender
  1040. {
  1041.                 // set the domain name
  1042.   domainname = [prefDomainName stringValue];
  1043.   return self;
  1044. }
  1045.  
  1046.  
  1047. // Change MTP server
  1048.  
  1049. - mtpServer:sender
  1050. {
  1051.                 // set the MTP server
  1052.   mtpserver = [prefMTPServer stringValue];
  1053.   return self;
  1054. }
  1055.  
  1056.  
  1057. // Change personal name
  1058.  
  1059. - personalName:sender
  1060. {
  1061.                 // set the personal name
  1062.   personalname = [prefPersonalName stringValue];
  1063.   return self;
  1064. }
  1065.  
  1066.  
  1067. // Change repository
  1068.  
  1069. - repository:sender
  1070. {
  1071.                 // set the repository
  1072.   repository = [prefRepository stringValue];
  1073.   return self;
  1074. }
  1075.  
  1076. // Change user name
  1077.  
  1078. - userName:sender
  1079. {
  1080.                 // set the user name
  1081.   username = [prefUserName stringValue];
  1082.   return self;
  1083. }
  1084.  
  1085. // Change default bcc list
  1086.  
  1087. - defaultBccList:sender
  1088. {
  1089.                 // set the default bcc list
  1090.   defaultbcc = [defaultBccList stringValue];
  1091.   return self;
  1092. }
  1093.  
  1094.  
  1095. // Change default cc list
  1096.  
  1097. - defaultCcList:sender
  1098. {
  1099.                 // set the default cc list
  1100.   defaultcc = [defaultCcList stringValue];
  1101.   return self;
  1102. }
  1103.  
  1104.  
  1105. // Change outbox
  1106.  
  1107. - outBox:sender
  1108. {
  1109.                 // set the outbox
  1110.   outbox = [outBox stringValue];
  1111.   return self;
  1112. }
  1113.  
  1114. // Change mailbox format
  1115.  
  1116. - mailboxFormat:sender
  1117. {
  1118.                 // set the format
  1119.   format = [mailboxFormat selectedRow];
  1120.   return self;
  1121. }
  1122.  
  1123. // Change automatic expunge state
  1124.  
  1125. - automaticExpunge:sender
  1126. {
  1127.                 // set the automatic expunge state
  1128.   autoexpunge = [automaticExpunge intValue];
  1129.   return self;
  1130. }
  1131.  
  1132.  
  1133. // Change automatic login state
  1134.  
  1135. - automaticLogin:sender
  1136. {
  1137.                 // set the automatic login state
  1138.   autologin = [automaticLogin intValue];
  1139.   return self;
  1140. }
  1141.  
  1142.  
  1143. // Change automatic open state
  1144.  
  1145. - automaticOpen:sender
  1146. {
  1147.                 // set the automatic open state
  1148.   autoopen = [automaticOpen intValue];
  1149.   return self;
  1150. }
  1151.  
  1152.  
  1153. // Change automatic read state
  1154.  
  1155. - automaticRead:sender
  1156. {
  1157.                 // set the automatic read state
  1158.   autoread = [automaticRead intValue];
  1159.   return self;
  1160. }
  1161.  
  1162.  
  1163. // Change automatic zoom state
  1164.  
  1165. - automaticZoom:sender
  1166. {
  1167.                 // set the automatic zoom state
  1168.   autozoom = [automaticZoom intValue];
  1169.   return self;
  1170. }
  1171.  
  1172. // Change close final kill state
  1173.  
  1174. - closeFinalKill:sender
  1175. {
  1176.                 // set the close final kill state
  1177.   closefinalkill = [closeFinalKill intValue];
  1178.   return self;
  1179. }
  1180.  
  1181.  
  1182. // Change debugging state
  1183.  
  1184. - debug:sender
  1185. {
  1186.   debug = [debugging intValue];    // set the debugging state
  1187.   return self;
  1188. }
  1189.  
  1190.  
  1191. // Change literal display state
  1192.  
  1193. - literalDisplay:sender
  1194. {
  1195.                 // set the literal display state
  1196.   literaldisplay = [literalDisplay intValue];
  1197.   return self;
  1198. }
  1199.  
  1200.  
  1201. // Change no line breaking state
  1202.  
  1203. - noLineBreaking:sender
  1204. {
  1205.                 // set the no line breaking state
  1206.   nolinebreaking = [noLineBreaking intValue];
  1207.   return self;
  1208. }
  1209.  
  1210.  
  1211. // Change no personal names state
  1212.  
  1213. - noPersonalNames:sender
  1214. {
  1215.                 // set the no personal names state
  1216.   nopersonal = [noPersonalNames intValue];
  1217.   return self;
  1218. }
  1219.  
  1220. // Change check interval
  1221.  
  1222. - checkInterval:sender
  1223. {
  1224.                 // get the interval
  1225.   interval = [checkInterval doubleValue];
  1226.                 // shove back after sanity check
  1227.   [checkInterval setDoubleValue:
  1228.    interval = interval > 0 ? (interval < sane ? sane : interval) : 0];
  1229.   return self;
  1230. }
  1231.  
  1232.  
  1233. // Open preferences panel
  1234.  
  1235. - preferences:sender
  1236. {
  1237.                 // create preferences panel if don't have one
  1238.   if (!preferencesPanel) [NXApp loadNibSection:"Preferences.nib"
  1239.               owner:self withNames:NIL];
  1240.   [preferencesPanel orderFront:self];
  1241.   return self;
  1242. }
  1243.  
  1244.  
  1245. // Open preferences help panel
  1246.  
  1247. - helpPreferences:sender
  1248. {
  1249.                 // attach to preferences panel
  1250.   [preferencesHelp attachWindow:[sender window]];
  1251.                 // open the sucker up
  1252.   [preferencesHelp orderFront:self];
  1253.   return self;
  1254. }
  1255.  
  1256. // Save the preferences
  1257.  
  1258. - savePreferences:sender
  1259. {
  1260.   NXDefaultsVector defaults = {
  1261.     {"AutomaticExpunge",[automaticExpunge intValue] ? "YES" : "NO"},
  1262.     {"AutomaticLogin",[automaticLogin intValue] ? "YES" : "NO"},
  1263.     {"AutomaticOpen",[automaticOpen intValue] ? "YES" : "NO"},
  1264.     {"AutomaticRead",[automaticRead intValue] ? "YES" : "NO"},
  1265.     {"AutomaticZoom",[automaticZoom intValue] ? "YES" : "NO"},
  1266.     {"CheckInterval",(char *) [checkInterval stringValue]},
  1267.     {"CloseFinalKill",[closeFinalKill intValue] ? "YES" : "NO"},
  1268.     {"DebugProtocol",[debugging intValue] ? "YES" : "NO"},
  1269.     {"DefaultBccList",(char *) [defaultBccList stringValue]},
  1270.     {"DefaultCcList",(char *) [defaultCcList stringValue]},
  1271.     {"DomainName",(char *) [prefDomainName stringValue]},
  1272.     {"LiteralDisplay",[literalDisplay intValue] ? "YES" : "NO"},
  1273.     {"MailboxFormat",format ? "mtxt" : "mbox"},
  1274.     {"MTPServer",(char *) [prefMTPServer stringValue]},
  1275.     {"NoLineBreaking",[noLineBreaking intValue] ? "YES" : "NO"},
  1276.     {"NoPersonalNames",[noPersonalNames intValue] ? "YES" : "NO"},
  1277.     {"OutBox",(char *) [outBox stringValue]},
  1278.     {"PersonalName",(char *) [prefPersonalName stringValue]},
  1279.     {"Repository",(char *) [prefRepository stringValue]},
  1280.     {"UserName",(char *) [prefUserName stringValue]},
  1281.     {NIL}
  1282.   };
  1283.                 // write the new default preferences
  1284.   if (!(NXWriteDefaults ([NXApp appName],defaults)))
  1285.     NXRunAlertPanel ("Save failed","Can't write preferences",NIL,NIL,NIL);
  1286.   return self;
  1287. }
  1288.  
  1289. // Open the address book
  1290.  
  1291. - addressBook:sender
  1292. {
  1293.                 // create address book if don't have one
  1294.   if (!book) [NXApp loadNibSection:"AddressBook.nib"
  1295.           owner:(book = [AddressBook new]) withNames:NIL];
  1296.                 // reopen if not called from SendWindow
  1297.   if (sender) [[book window] orderFront:self];
  1298.   return book;            // return the address book
  1299. }
  1300.  
  1301.  
  1302. // Write to pasteboard
  1303.  
  1304. - setPasteboard:(char *) text
  1305. {
  1306.                 // only use ASCII types
  1307.   [pasteboard declareTypes:&NXAsciiPboard num:1 owner:[self class]];
  1308.   [pasteboard writeType:NXAsciiPboard data:text length:strlen (text)];
  1309.   return self;
  1310. }
  1311.  
  1312.  
  1313. // User wants to quit, maybe
  1314.  
  1315. extern STREAMPROP *streamproplist;
  1316. - terminate:sender
  1317. {                // work around 1.0 bug (fix pasteboard owner)
  1318. //[pasteboard declareTypes:&NXAsciiPboard num:1 owner:[self class]];
  1319.   if (lockedopen && opener) {    // any locked open window?
  1320.     if (!NXRunAlertPanel ("Quit?","Do you really want to Quit?",NIL,"Cancel",
  1321.               NIL)) return self;
  1322.     [opener exit:self];        // yes, close it always
  1323.   }
  1324.   if (streamproplist)
  1325.     switch (NXRunAlertPanel ("Quit?","Close open mailboxes, save changes?",
  1326.                  "Save","Don't Save","Cancel")) {
  1327.     case NX_ALERTOTHER:        // Cancel
  1328.       return self;        // punt
  1329.     case NX_ALERTDEFAULT:    // Close
  1330.       while (streamproplist)    // do an Exit on all streams
  1331.     [(getstreamprop (streamproplist->stream))->window exit:NIL];
  1332.     case NX_ALERTALTERNATE:    // Don't close
  1333.     case NX_ALERTERROR:        // some error
  1334.     default:
  1335.       break;
  1336.   }
  1337.   [super terminate:sender];    // sayonara
  1338.   return self;
  1339. }
  1340.  
  1341. // mdd
  1342.  
  1343. - toggleTelemetry:sender
  1344. {
  1345.     id window = [telemetryView window];
  1346.     
  1347.     if ([window isVisible])
  1348.         [window orderOut:self];
  1349.     else
  1350.         [window orderFront:self];
  1351.     [[windowMenu target] update];
  1352.     return self;
  1353. }
  1354.  
  1355. - (BOOL)updateTelemetryMenu:menuCell
  1356. {
  1357.     BOOL telemVisible = telemetryView && [[telemetryView window] isVisible];
  1358.     BOOL menuSaysHide = strcmp([menuCell title], "Show Telemetry");
  1359.  
  1360.     if (telemVisible == menuSaysHide)
  1361.         return NO;
  1362.     else {
  1363.         [menuCell setTitle:(telemVisible ? "Hide Telemetry":"Show Telemetry")];
  1364.         return YES;
  1365.     }
  1366. }
  1367.  
  1368. @end
  1369.